package com.open.lock.utils;

import com.open.lock.exception.LockException;
import com.open.lock.expression.ExpressionResolver;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhang kaichao
 */
public final class LockUtil {

    public static final String IDEMPOTENT = "IDEMPOTENT::%s";

    public static final String LOCK = "LOCK::%s";

    /**
     * keys数组转换为list
     *
     * @param keys 数组
     * @return 集合
     */
    public static List<String> keysToList(String... keys) {
        if (keys == null) {
            throw new LockException("Lock ==> keys is null.");
        }
        List<String> keyList = Stream.of(keys).filter(f -> f != null && !"".equals(f)).collect(Collectors.toList());
        if (keyList.isEmpty()) {
            throw new LockException("Lock ==> keys is empty.");
        }
        return keyList;
    }

    /**
     * keys数组转换为list
     *
     * @param keys 数组
     * @return 集合
     */
    public static List<String> keysToListNoThrow(String... keys) {
        if (keys == null) {
            return Collections.emptyList();
        }
        List<String> keyList = Stream.of(keys).filter(f -> f != null && !"".equals(f)).collect(Collectors.toList());
        if (keyList.isEmpty()) {
            return Collections.emptyList();
        }
        return keyList;
    }

    /**
     * 生成key
     *
     * @param joinPoint 切面
     * @param keys      参数
     * @return 缓存键
     */
    public static String createKey(ProceedingJoinPoint joinPoint, String... keys) {
        List<String> keyList = LockUtil.keysToListNoThrow(keys);
        List<String> result;
        if (keyList.isEmpty()) {
            result = Arrays.stream(joinPoint.getArgs()).map(m -> {
                if (m == null) {
                    return "";
                }
                return m.toString();
            }).filter(f -> f != null && !"".equals(f)).collect(Collectors.toList());
        } else {
            result = keyList.stream().map(m -> {
                if (m.startsWith("#")) {
                    return ExpressionResolver.resolver(m, joinPoint);
                } else {
                    return m;
                }
            }).filter(f -> f != null && !"".equals(f)).collect(Collectors.toList());
        }
        if (result.isEmpty()) {
            return "";
        }
        String paramKey = String.join(":", result);
        return determineKey(paramKey);
    }

    public static String[] createLockKey(ProceedingJoinPoint joinPoint, String... keys) {
        List<String> keyList = LockUtil.keysToList(keys);
        return keyList.stream().map(m -> {
            if (m.startsWith("#")) {
                return ExpressionResolver.resolver(m, joinPoint);
            } else {
                return m;
            }
        }).filter(f -> f != null && !"".equals(f)).toArray(String[]::new);
    }

    private static String determineKey(String requestParam) {
        return String.format(IDEMPOTENT, requestParam);
    }

    public static String lockKey(String requestParam) {
        return String.format(LOCK, requestParam);
    }
}
